package edu.pku.sei.transformation.qvt.adapter;

import java.util.ArrayList;
import java.util.List;

import edu.pku.sei.transformation.editor.model.GraphicalDomain;
import edu.pku.sei.transformation.editor.model.Rule;
import edu.pku.sei.transformation.editor.model.RuleInvoke;
import edu.pku.sei.transformation.editor.model.RuleInvokeParameter;
import edu.pku.sei.transformation.editor.model.variable.PrimitiveTypeVariable;
import edu.pku.sei.transformation.qvt.rule.IDomain;
import edu.pku.sei.transformation.qvt.rule.IObjectTemplate;
import edu.pku.sei.transformation.qvt.rule.IPrimitiveDomain;
import edu.pku.sei.transformation.qvt.rule.IRelation;
import edu.pku.sei.transformation.qvt.rule.ITransformation;

public class RelationAdapter implements IRelation {
	protected Rule element;
	protected List<IDomain> domains;
	protected List<IPrimitiveDomain> primitiveDomains;
	protected ITransformation owner;
	public RelationAdapter(Rule r) {
		element = r;
		domains = new ArrayList<IDomain>();
		for (Object obj : r.getDomains()) {
			if (obj instanceof GraphicalDomain) {
				domains.add(new DomainAdapter((GraphicalDomain) obj));
			} else {
				System.err.println("illegal domain type");
			}
		}
		
		primitiveDomains = new ArrayList<IPrimitiveDomain>();
		for(Object obj : element.getVariables()) {
			if (obj instanceof PrimitiveTypeVariable) {
				if (((PrimitiveTypeVariable) obj).isVisible()) {
					primitiveDomains.add(new PrimitiveDomainAdapter((PrimitiveTypeVariable) obj));
				}
			} else {
				System.err.println("illegal variable type");
			}
		}
	}
	@Override
	public List<IDomain> getDomains() {
		return this.domains;
	}

	@Override
	public String getName() {
		return element.getName();
	}

	@Override
	public List<String> getVariables() {
		ArrayList<String> list = new ArrayList<String>();
		for(Object obj : element.getVariables()) {
			if (obj instanceof PrimitiveTypeVariable) {
				if (((PrimitiveTypeVariable) obj).isVisible() == false) {
					String s = ((PrimitiveTypeVariable)obj).toString()+";";
					list.add(s);
				}
			} else {
				System.err.println("illegal variable type");
			}
		}
		return list;
	}

	@Override
	public List<String> getWhen() {
		ArrayList<String> list = new ArrayList<String>();
		for (Object obj : element.getInvoke()) {
			RuleInvoke invoke = (RuleInvoke) obj;
			if (invoke.getInvokeType() == RuleInvoke.RULE_PRECONDITION) {
				String s = getInvokeString(invoke);
				if (s != null && !s.equals("")) {
					list.add(s);
				}
			}
		}
		return list;
	}

	@Override
	public List<String> getWhere() {
		ArrayList<String> list = new ArrayList<String>();
		for (Object obj : element.getBody()) {
			list.add(obj.toString());
		}
		
		for (Object obj : element.getInvoke()) {
			RuleInvoke invoke = (RuleInvoke) obj;
			if (invoke.getInvokeType() == RuleInvoke.RULE_POSTCONDITION) {
				String s = getInvokeString(invoke);
				if (s != null && !s.equals("")) {
					list.add(s);
				}
			}
		}
		return list;
	}

	@Override
	public boolean isTopLevel() {
		if (element.getPriority() == 1)
			return true;
		else
			return false;
	}
	
	private String getInvokeString(RuleInvoke invoke) {
		String s = "";
		IRelation callee = owner.getRelationByName(invoke.getCallee().getName());
		if (invoke.getParameters().size() == callee.getAllDomains().size()) {
			s += callee.getName();
			s +="(";
			boolean haveParem = false;
			for (Object obj : callee.getAllDomains()) {
				String name = "";
				if (obj instanceof IDomain) {
					IDomain domain = (IDomain) obj;
					IObjectTemplate root = domain.getRootElement();
					if (root == null) {
						System.err.println("empty domain");
						return "";
					} else {
						name = root.getName();
					}
				} else if (obj instanceof IPrimitiveDomain) {
					name = ((IPrimitiveDomain)obj).getName();
				} else {
					System.err.println("unknow domain type");
					return "";
				}
				boolean find = false;
				for (Object obj2 : invoke.getParameters()) {
					RuleInvokeParameter p = (RuleInvokeParameter) obj2;
					if (p.getFormalParameter().getName().equals(name)) {
						find = true;
						if (haveParem) {
							s+= ", ";
						} else {
							haveParem = true;
						}
						if (p.getActualParameterString().endsWith(";"))
							s+=p.getActualParameterString().substring(0, p.getActualParameterString().length()-1);
						else
							s+=p.getActualParameterString();
						break;
					}
				}
				if (!find) {
					System.err.println("can not find domain "+name+" actual parameter");
					return "";
				}
			}
			s+=");";
		} else {
			System.err.println("parameter number is incorrect caller:"+invoke.getCaller().getName()+" callee:"+invoke.getCallee().getName());
		}
		
		return s;
	}
	@Override
	public List<IPrimitiveDomain> getPrimitiveDomains() {
		return primitiveDomains;
	}
	
	public List getAllDomains() {
		ArrayList list = new ArrayList();
		list.addAll(domains);
		list.addAll(primitiveDomains);
		return list;
	}
	@Override
	public ITransformation getOwner() {
		return owner;
	}
	@Override
	public void setOwner(ITransformation owner) {
		this.owner = owner;
	}

}
